/*
 * shiftregister.c
 *
 * Created: 06.09.2011 19:23:09
 *  Author: halfmann
 */ 

#include "shiftregister.h"
#include <util/delay.h>


//Array fuer die Daten einer Ebene
unsigned char shiftregisterData[SHIFTREGISTER_BYTES];

//Belegt die Ausgaenge 
void shiftregister_init (void)
{
    //Verwendete Pins des Controllers als Ausgang setzen
	SHIFTREGISTER_SER_DDR |= (1 << SHIFTREGISTER_SER_PIN);
	SHIFTREGISTER_SCK_DDR |= (1 << SHIFTREGISTER_SCK_PIN);
	SHIFTREGISTER_RCK_DDR |= (1 << SHIFTREGISTER_RCK_PIN);
    
    //SCK und RCK auf definierten Level HIGH setzen
	SHIFTREGISTER_SCK_PORT |= (1 << SHIFTREGISTER_SCK_PIN);
	SHIFTREGISTER_RCK_PORT |= (1 << SHIFTREGISTER_RCK_PORT);
}

//Laedt die Daten in shiftregisterData in die Schieberegister
void shiftregister_out (void)
{
    unsigned char anz = SHIFTREGISTER_BYTES;
	/* Pointer setzen */
    unsigned char* serp = shiftregisterData+SHIFTREGISTER_BYTES;

    do
    {
        unsigned char bits;
		/* Pointer zeigt auf aktuelles Datenelement und wird dekrementiert */
        unsigned char data = *--serp;

        /* 8 Bits pro Byte herausschieben */
        for (bits = 8; bits > 0; bits--)
        {			
            SHIFTREGISTER_SER_PORT &= ~(1 << SHIFTREGISTER_SER_PIN);
            if (data & 0x80)
            {
                SHIFTREGISTER_SER_PORT |= (1 << SHIFTREGISTER_SER_PIN);
            }

            data <<= 1;
            /* Strobe an SCK schiebt Daten im Gaensemarsch */
            /* um 1 Position weiter durch alle Schieberegister */
            SHIFTREGISTER_SCK_PORT &= ~(1 << SHIFTREGISTER_SCK_PIN);
			//_delay_ms(500);
            SHIFTREGISTER_SCK_PORT |= (1 << SHIFTREGISTER_SCK_PIN);
			//_delay_ms(500);
        }
    }
    while (--anz > 0);

    shiftregister_out_push_Data_to_output();
}

//Nimmt ein Array mit Daten fuer die Schieberegister entgegen 
void shiftregister_out_alternate (volatile uint8_t inputData[])
{
    unsigned char anz = SHIFTREGISTER_BYTES;
	//Pointer setzen
    unsigned char* serp = inputData+SHIFTREGISTER_BYTES;

    do
    {
        unsigned char bits;
		//Pointer zeigt auf aktuelles Datenelement und wird dekrementiert
        unsigned char data = *--serp;

        //8 Bits pro Byte herausschieben
        for (bits = 8; bits > 0; bits--)
        {			
            SHIFTREGISTER_SER_PORT &= ~(1 << SHIFTREGISTER_SER_PIN);
            //if (data & 0x80)
			if (data & 0x01)
            {
                SHIFTREGISTER_SER_PORT |= (1 << SHIFTREGISTER_SER_PIN);
            }

            //data <<= 1;
			data >>=1;
            //Strobe an SCK schiebt Daten im Gaensemarsch
            //um 1 Position weiter durch alle Schieberegister
            SHIFTREGISTER_SCK_PORT &= ~(1 << SHIFTREGISTER_SCK_PIN);
			//_delay_ms(500);
            SHIFTREGISTER_SCK_PORT |= (1 << SHIFTREGISTER_SCK_PIN);
			//_delay_ms(500);
        }
    }
    while (--anz > 0);    
	
	//shiftregister_out_push_Data_to_output();
}

//kurzer Puls an RCK bringt die Daten der Schieberegistern in die Ausgangs-Latches
void shiftregister_out_push_Data_to_output()
{
    SHIFTREGISTER_RCK_PORT &= ~(1 << SHIFTREGISTER_RCK_PIN);
	//_delay_us(1); Delay ist nicht noetig - funktioniert auch ohne
    SHIFTREGISTER_RCK_PORT |= (1 << SHIFTREGISTER_RCK_PIN);
}